﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Concurrent;
using System.Threading;
using Messaging2;
using s = FinPlusStructure.FinPlusStructure;
using u = FinPlusUtility.Utility;

namespace FinPlusQuoteRouter
{
    public class Generate
    {
        private ITransport _tran;
        private Instruments _instruments;
        private u.Config _config;
        private u.Env _env;
        private int _wait;

        //construct
        public Generate(ITransport tran, u.Env env, u.Config config, int waitMilliseconds)
        {
            _tran = tran;
            _env = env;
            _config = config;
            _wait = waitMilliseconds;
            _instruments = new Instruments();
        }

        public void Publish()
        {
            try
            {
                do
                {
                    //Parallel.ForEach(_config.Values, product =>
                    foreach (var product in _config.Values)
                    {
                        if(product.ContainsKey("Instrument")) 
                        {
                            var rnd = new Random();
                           
                            double value = double.Parse(product["Level"]);
                            double open = double.Parse(product["Open"]);
                            double limit = double.Parse(product["Limit"]);
                            double step = double.Parse(product["RandomStep"]);
                            double newValue = rnd.Next(0, 2) == 0 ? value - step : value + step;

                            if (newValue < open - limit || newValue > open + limit)
                                newValue = value;
                            else
                                product["Level"] = newValue.ToString();

                            var instr = product["Instrument"];
                            var quoteType= product["QuoteType"];
                            var rateType = product["RateType"];
                            var quoteStyles = product["QuoteStyle"].Split(',');
                            var buySellFactor = int.Parse(product["BuySellFactor"]);
                            var size = double.Parse(product["Size"]);
                            var sizeFactor = int.Parse(product["SizeFactor"]);
                            
                            var count = 0;
                            var instruments = _instruments[instr] = !_instruments.ContainsKey(instr) ? new Owners() : _instruments[instr];
                            foreach (var owner in product["QuoteSource"].Split(','))
                            {
                                var counterpartys = instruments[owner] = !instruments.ContainsKey(owner) ? new Counterpartys() : instruments[owner];
                                foreach (var counterparty in product["Counterparty"].Split(','))
                                {
                                    var quoteBuySell = counterpartys[counterparty] = !counterpartys.ContainsKey(counterparty) ? new BuySell() : counterpartys[counterparty];
                                    foreach (var buySellName in product["BuySell"].Split(','))
                                        BuySell(rnd, quoteBuySell, buySellName, newValue, step, buySellFactor, size, instr, quoteType, owner, quoteStyles[count], rateType, counterparty, sizeFactor);
                                }
                                count++;
                            }
                        }
                    }
                    //});
                }
                while (true);
            }
            catch
            {
                throw;
            }
        }

        private void BuySell(Random rnd, BuySell buySell, string name, double value, double step, int factor, double size, string instName, string quoteType, string owner, string quoteStyle, string rateType, string counterparty, int sizeFactor)
        {
            Thread.Sleep(_wait);
            var quote = new Quote(u.Guid(), value + (name.Equals("Buy") ? -1 : 1) * step * rnd.Next(0, factor), size * rnd.Next(1, sizeFactor));
            if (buySell.ContainsKey(name))
            {
                if (buySell[name].Equals(quote)) return;
                Quote oldQuote = null;
                buySell.TryRemove(name, out oldQuote);

                //cancel quote
                _tran.Publish(new Message(s.QuoteCancel(oldQuote.Reference).ToArray(), string.Format("{0}.{1}.Quote", _env, owner)));
            }

            //new quote
            _tran.Publish(new Message(s.Quote(quote.Reference, instName, name, quote.Level, quote.Size, quoteStyle, quoteType, rateType, owner, counterparty).ToArray(), string.Format("{0}.{1}.Quote", _env, owner)));
            buySell[name] = quote;
        }
    }

    public class Instruments : ConcurrentDictionary<string, Owners> {}

    public class Owners : ConcurrentDictionary<string, Counterpartys>{}

    public class Counterpartys : ConcurrentDictionary<string, BuySell>{}

    public class BuySell : ConcurrentDictionary<string, Quote>{}

    public class Quote
    {
        public double Level { get; set; }
        public double Size { get; set; }
        public string Reference { get; set; }

        public Quote(string reference, double level, double size)
        {
            Level = level;
            Size = size;
            Reference = reference;
        }

        bool Equals(Quote quote)
        {
            return quote.Size == Size && quote.Level == Level ? true : false;
        }
    }
}
